import PartnerContentLink from 'components/PartnerContentLink';

# Design principles

This page provides a deep dive about the design principles that `next-intl` is based on.

While this page doesn't need to be read in order to use the library effectively in a project, it can provide you with a better understanding of the philosophy behind the library and can help you evaluate if `next-intl` is a good fit for your project.

This page also links to planned improvements in order to act as a transparent reference for enhancements to expect from `next-intl` in the future.

## Holistic

Internationalization clearly requires flexibility from your codebase. However, even implementing a single language properly can already be a challenge by itself.

Using **dynamic text labels** is the most obvious aspect of internationalization, but supporting a language well also includes many other aspects:

1. **Pluralization rules**: While a language like English has only two plural forms (singular and plural), other languages have up to six different forms.
2. **Date and time formatting**: Different languages have different conventions for formatting dates and times. Even the year displayed can vary from country to country; for example, Thailand uses the Buddhist calendar, which is 543 years ahead of the Gregorian one.
3. **Number formatting**: Formatting conventions for numbers vary across different languages. For instance, when comparing English and German, the separators for thousands and decimals are flipped.
4. **List formatting**: Formatting lists like "HTML, CSS, and JavaScript" is not only a matter of assembling strings in the right order, but also of using language-specific conjunctions and punctuation marks.
5. **Text direction**: While most languages are written from left to right, some languages like Arabic are written from right to left and require a mirrored layout.

On top of this come typical app problems like:

1. **Rich text formatting**: Many apps need to support some way of rich text, e.g. to embed links into text labels ("Learn more in [the rich text docs](/docs/usage/messages#rich-text).").
2. **Time zones**: Displaying dates requires consistent handling of time zones across the server and client, potentially even customized based on a preference of the user.
3. **Relative time formatting**: Displaying relative times like "5 minutes ago" or "in 2 hours" requires special care to get the formatting right, and also to make sure the rendered result is in sync across the server and client. Potentially, you also need a mechanism to update the displayed time regularly.
4. **Localized URLs**: URLs should be localized to match the user's language preference (e.g. `/en/about-us` for English and `/es/sobre-nosotros` for Spanish). Implementation-wise this requires mapping incoming requests to the right pages and providing streamlined APIs for developers to link between pages in a locale-agnostic way.
5. **Language negotiation**: The user's language preference should be detected based on browser settings, but should also be manually configurable—even if a user hasn't signed in.
6. **SEO**: Search engines need to be informed about [localized versions of your pages](https://developers.google.com/search/docs/specialty/international/localized-versions) in order to present the best-matching content to your users.
7. **Country-specifics**: If you provide services or products in different countries, you might need to consider country-specifics like different currencies.

Considering this list, it might be apparent how large the problem space is and how interconnected different pieces of internationalization are.

`next-intl` takes a holistic approach to internationalization that nudges you towards best practices for handling languages and country-specific conventions. This way, you have more time to focus on what makes your app unique.

→ [Planned enhancements](https://github.com/amannn/next-intl/labels/area%3A%20routing)

## Ergonomic

The bold claim of this library is that your app code will become simpler instead of more complex when you implement internationalization.

If you consider [the holistic picture](/docs/design-principles#holistic) of what internationalization entails, it's clear that a majority of your components will be involved with internationalization in one way or another. Due to this, `next-intl` makes it a priority to provide convenient APIs that ensure you feel productive and in control. As a developer, you should be able to focus solely on solving practical problems, with internationalization seamlessly integrated as a side effect of your efforts.

Once internationalization is set up, adding a new language is in the simplest case only a matter of adding a new JSON file with translations—everything else is being taken care of by `next-intl`.

→ [Planned enhancements](https://github.com/amannn/next-intl/labels/area%3A%20ergonomics)

## Standards-based

With the introduction of [the ECMAScript Internationalization API](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Intl), JavaScript has gotten very capable in the recent years in regard to formatting of dates, times, numbers, lists and pluralization. `next-intl` builds on top of this API and provides an ergonomic interface to work with these features, while considering your app-specific configuration & needs.

For text formatting, `next-intl` is based on [International Components for Unicode (ICU)](https://unicode-org.github.io/icu/userguide/format_parse/). ICU is a mature and widely used standard for internationalization that is supported by many programming languages and frameworks. `next-intl` uses the ICU message syntax for defining text labels, which allows to express complex formatting requirements like interpolating variables and pluralization in a concise and readable way—also for non-developers like translators.

By being based on standards, `next-intl` ensures that your internationalization code is future-proof and feels familiar to developers who have existing experience with internationalization. Additionally, relying on standards ensures that `next-intl` integrates well with translation management systems like <PartnerContentLink href="https://crowdin.com/">Crowdin</PartnerContentLink>.

`next-intl` uses a [nested style](/docs/usage/messages#structuring-messages) to provide structure to messages, allowing to express hierarchies of messages without redundancy. By supporting only a single style, we can offer advanced features that rely on these assumptions like [type-safety for messages](/docs/workflows/typescript). If you're coming from a different style, you can consider migrating to the nested style (see "Can I use a different style for structuring my messages?" in [the structuring messages docs](/docs/usage/messages#structuring-messages)).

As standards can change, `next-intl` is expected to keep up with the latest developments in the ECMAScript standard (e.g. [`Temporal`](https://tc39.es/proposal-temporal/docs/) and [`Intl.MessageFormat`](https://github.com/tc39/proposal-intl-messageformat)).

→ [Planned enhancements](https://github.com/amannn/next-intl/labels/area%3A%20standards)

## Compatible

While `next-intl` is designed to tackle internationalization in [a holistic way](#holistic), it's important to consider that internationalization might require integration with other tools and services, enabling you to use the best tools for the job and to collaborate with non-developers.

Typical apps require some of the following integrations:

**Translation Management Systems (TMS)**

These are typically used to manage translations and to [collaborate with translators](/docs/workflows/localization-management). Services like <PartnerContentLink href="https://crowdin.com/">Crowdin</PartnerContentLink> provide a wide range of features, allowing translators to work in a web-based interface on translations, while providing different mechanisms to sync translations with your app.

`next-intl` integrates well with these services as it uses ICU message syntax for defining text labels, which is a widely supported standard. The recommended way to store messages is in JSON files that are structured by locale since this is a popular format that can be imported into a TMS. While it's recommended to have at least the messages for the default locale available locally (e.g. for [type-safe messages](/docs/workflows/typescript)), you can also load messages dynamically, e.g. from a CDN that your TMS provides.

**Content Management Systems (CMS)**

If your app uses content from a CMS, you can use this alongside `next-intl`. For instance, you might want to manage content like blog posts or marketing copy in a CMS, while managing UI labels in `next-intl`.

A CMS typically provides a way to define content for multiple languages, and to fetch this content via a REST API. By using the negotiated app locale that is returned from `next-intl` via [`getLocale`](/docs/environments/server-client-components#async-components) and passing it to requests to your CMS API, you can retrieve content for the user's preferred language.

**Backend data**

Similar to a CMS, you might have data in a backend service or database that needs to be queried based on the language and country of the user. For instance, you might want to show different prices & currencies for different countries, or you might want to show localized product names. By using the negotiated app locale from `next-intl` for requests to your backend, you can ensure localization reaches all parts of your app.

**Other libraries**

Next.js has a rich ecosystem of libraries that can be used alongside `next-intl`, e.g. to handle authentication. By providing [documentation and examples for common integrations](/docs/routing/middleware#composing-other-middlewares), `next-intl` ensures that you'll have a frictionless experience when integrating with other libraries.

→ [Planned enhancements](https://github.com/amannn/next-intl/labels/area%3A%20integrations)

## Performance-obsessed

`next-intl` was designed with high-traffic sites in mind that need to deliver a fast and reliable user experience and has proven to work on complex e-commerce pages with outstanding Core Web Vitals.

To achieve this, `next-intl` primarly relies on these techniques currently:

1. **RSC-first**: By integrating deeply with React Server Components, we can offload work to a build step or a capable server, therefore reducing the runtime footprint of your app on the client side.
2. **Splitting of messages**: By splitting messages by locale, and optionally also by server, client and component, we can reduce the amount of messages that are sent to the client. This is especially important for apps that support many languages and have a large amount of messages.
3. **Caching**: Parsing of messages, as well as the instantiation of [`Intl`](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Intl) constructors is cached across your app, therefore reducing the amount of necessary computation.
4. **Shortcuts**: By detecting plain messages, these messages can be returned immediately without having to parse them first.

→ [Planned enhancements](https://github.com/amannn/next-intl/labels/area%3A%20performance)

## Next.js-first

Next.js comes with a lot of bells and whistles, but at the same time there are a number of aspects that need to be handled carefully to enable a reliable internationalization integration. `next-intl`, as the name implies, is primarly designed to work well with Next.js. Rather than trying to be a one-size-fits-all solution, `next-intl` integrates with Next.js as deeply as necessary and makes it a priority to stay on top of the latest developments in the Next.js ecosystem.

That being said, `next-intl` has a Next.js-agnostic core that can be used in any React app, or even in plain JavaScript: [`use-intl`](/docs/environments/core-library). This core library contains most features of `next-intl`, but lacks Next.js-specific integrations like routing APIs. The goal of this library is to make it possibly to use familiar APIs in other parts of your stack (e.g. React Native) and, in case you ever feel like Next.js is not the right fit for your project anymore, to provide a straightforward [migration path](#migration-friendly).

## Migration-friendly

We've all been there, technology moves on, and sometimes you need to move on as well. `next-intl` is designed to be a good citizen in your codebase, and to make it possible to migrate away from certain parts of your stack in case this becomes necessary.

If you ever feel like Next.js or `next-intl` is not the right fit for your project anymore, you have multiple options here:

1. **Moving away from Next.js**: If you decide to migrate away from Next.js, you can continue to use the core library [`use-intl`](/docs/environments/core-library) in any React app, e.g. allowing you to reuse existing components in [a Remix app](/examples#remix).
2. **Moving away from `next-intl`**: If you find that `next-intl` doesn't fit your needs anymore, you'll have to adapt app code that references the library, but you can still reuse your [standards-based](#standards-based) ICU messages and replace formatting APIs e.g. with direct calls to the [ECMAScript Internationalization API](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Intl).

We wont hold you back, but if you like, we can stay friends.

That being said, we're doing our best to make `next-intl` a great fit for your project. If you ever feel like something is not working as expected or if you have ideas for improvements, please let us know on the [issue tracker](https://github.com/amannn/next-intl/issues) and we'll do our best to help you out.

---

Woah, this was a long read. Did you really read all of this? `next-intl` was created out of a lot of curiosity and passion for internationalization, seems like we share that! We're always curious to hear how `next-intl` is working out for you. If you have any feedback or questions, please don't hesitate to [reach out](https://github.com/amannn/next-intl/discussions)!
